class NoteEvent {
  Index
  Beat
  LineIndex
  LineLayer
  Type
  CutDirection
}

class WallEvent {
  Index
  Beat
  RotationLane
  Duration
  LineIndex
  LineLayer
  Width
  Height
}

class BeatMapParser {
  data
  info
  noteEvents = []
  wallEvents = []

  constructor(info, data) {
    this.info = info
    this.data = data

    // Init Note Events
    this.initNoteEvents()
    // Sort the Note Events by beat
    this.noteEvents.sort((a, b) => a.Beat - b.Beat)

    this.initWallEvents()
    // Sort the Wall Events by beat
    this.wallEvents.sort((a, b) => a.Beat - b.Beat)
  }

  initNoteEvents() {
    throw "initNoteEvents not implemented!"
  }

  initWallEvents(){
    throw "initWallEvents not implemented!"
  }

  static RawTimeFromBeat(beat, bpm) {
    if (bpm <= 0) return 0;
    return beat / bpm * 60;
  }

  static RawBeatFromTime(time, bpm) {
    if (bpm <= 0) return 0;
    return time / 60 * bpm;
  }

  BeatFromTime(time) {
    return BeatMapParser.RawBeatFromTime(time, this.info.getRawBpm())
  }

  TimeFromBeat(beat) {
    return BeatMapParser.RawTimeFromBeat(beat, this.info.getRawBpm())
  }

  getBpmFromBeat(beat) {
    return this.info.getRawBpm()
  }

  internalRunOnRangeEvents(events, startBeat, endBeat, func){
    let lower = events.findIndex(noteEvent => noteEvent.Beat >= startBeat);
    let upper = events.findIndex(noteEvent => noteEvent.Beat > endBeat);

    if(events.length == 1){
       if(events[0].Beat >= startBeat && events[0].Beat < endBeat){
         lower = 0;
         upper = 1;
       }
    }

    if(lower == -1 || upper == -1)
      return

    for(let i = lower; i< upper; i++){
      func(events[i])
    }
  }

  runOnRangeNotes(startBeat, endBeat, func){
    this.internalRunOnRangeEvents(this.noteEvents, startBeat, endBeat, func)
  }

  runOnRangeWalls(startBeat, endBeat, func){
    this.internalRunOnRangeEvents(this.wallEvents, startBeat, endBeat, func)
  }
}

export {
  BeatMapParser,
  NoteEvent,
  WallEvent
}